1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.collect.CollectPreconditions.checkEntryNotNull;
21 import static com.google.common.collect.Iterables.getOnlyElement;
22
23 import java.io.Serializable;
24 import java.util.Collections;
25 import java.util.EnumMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29
30 import javax.annotation.Nullable;
31
32
33
34
35
36
37
38
39
40
41
42
43 public abstract class ImmutableMap<K, V> implements Map<K, V>, Serializable {
44
45 ImmutableMap() {}
46
47 public static <K, V> ImmutableMap<K, V> of() {
48 return ImmutableBiMap.of();
49 }
50
51 public static <K, V> ImmutableMap<K, V> of(K k1, V v1) {
52 return ImmutableBiMap.of(k1, v1);
53 }
54
55 public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) {
56 return new RegularImmutableMap<K, V>(entryOf(k1, v1), entryOf(k2, v2));
57 }
58
59 public static <K, V> ImmutableMap<K, V> of(
60 K k1, V v1, K k2, V v2, K k3, V v3) {
61 return new RegularImmutableMap<K, V>(
62 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
63 }
64
65 public static <K, V> ImmutableMap<K, V> of(
66 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
67 return new RegularImmutableMap<K, V>(
68 entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4));
69 }
70
71 public static <K, V> ImmutableMap<K, V> of(
72 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
73 return new RegularImmutableMap<K, V>(entryOf(k1, v1),
74 entryOf(k2, v2), entryOf(k3, v3), entryOf(k4, v4), entryOf(k5, v5));
75 }
76
77
78
79 public static <K, V> Builder<K, V> builder() {
80 return new Builder<K, V>();
81 }
82
83 static <K, V> Entry<K, V> entryOf(K key, V value) {
84 checkEntryNotNull(key, value);
85 return Maps.immutableEntry(key, value);
86 }
87
88 public static class Builder<K, V> {
89 final List<Entry<K, V>> entries = Lists.newArrayList();
90
91 public Builder() {}
92
93 public Builder<K, V> put(K key, V value) {
94 entries.add(entryOf(key, value));
95 return this;
96 }
97
98 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
99 if (entry instanceof ImmutableEntry) {
100 checkNotNull(entry.getKey());
101 checkNotNull(entry.getValue());
102 @SuppressWarnings("unchecked")
103 Entry<K, V> immutableEntry = (Entry<K, V>) entry;
104 entries.add(immutableEntry);
105 } else {
106 entries.add(entryOf((K) entry.getKey(), (V) entry.getValue()));
107 }
108 return this;
109 }
110
111 public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
112 for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
113 put(entry.getKey(), entry.getValue());
114 }
115 return this;
116 }
117
118 public ImmutableMap<K, V> build() {
119 return fromEntryList(entries);
120 }
121
122 private static <K, V> ImmutableMap<K, V> fromEntryList(
123 List<Entry<K, V>> entries) {
124 int size = entries.size();
125 switch (size) {
126 case 0:
127 return of();
128 case 1:
129 Entry<K, V> entry = getOnlyElement(entries);
130 return of(entry.getKey(), entry.getValue());
131 default:
132 @SuppressWarnings("unchecked")
133 Entry<K, V>[] entryArray
134 = entries.toArray(new Entry[entries.size()]);
135 return new RegularImmutableMap<K, V>(entryArray);
136 }
137 }
138 }
139
140 public static <K, V> ImmutableMap<K, V> copyOf(
141 Map<? extends K, ? extends V> map) {
142 if ((map instanceof ImmutableMap) && !(map instanceof ImmutableSortedMap)) {
143 @SuppressWarnings("unchecked")
144 ImmutableMap<K, V> kvMap = (ImmutableMap<K, V>) map;
145 return kvMap;
146 } else if (map instanceof EnumMap) {
147 EnumMap<?, ?> enumMap = (EnumMap<?, ?>) map;
148 for (Map.Entry<?, ?> entry : enumMap.entrySet()) {
149 checkNotNull(entry.getKey());
150 checkNotNull(entry.getValue());
151 }
152 @SuppressWarnings("unchecked")
153
154 ImmutableMap<K, V> result = ImmutableEnumMap.asImmutable(new EnumMap(enumMap));
155 return result;
156 }
157
158 int size = map.size();
159 switch (size) {
160 case 0:
161 return of();
162 case 1:
163 Entry<? extends K, ? extends V> entry
164 = getOnlyElement(map.entrySet());
165 return ImmutableMap.<K, V>of(entry.getKey(), entry.getValue());
166 default:
167 Map<K, V> orderPreservingCopy = Maps.newLinkedHashMap();
168 for (Entry<? extends K, ? extends V> e : map.entrySet()) {
169 orderPreservingCopy.put(
170 checkNotNull(e.getKey()), checkNotNull(e.getValue()));
171 }
172 return new RegularImmutableMap<K, V>(orderPreservingCopy);
173 }
174 }
175
176 abstract boolean isPartialView();
177
178 public final V put(K k, V v) {
179 throw new UnsupportedOperationException();
180 }
181
182 public final V remove(Object o) {
183 throw new UnsupportedOperationException();
184 }
185
186 public final void putAll(Map<? extends K, ? extends V> map) {
187 throw new UnsupportedOperationException();
188 }
189
190 public final void clear() {
191 throw new UnsupportedOperationException();
192 }
193
194 @Override
195 public boolean isEmpty() {
196 return size() == 0;
197 }
198
199 @Override
200 public boolean containsKey(@Nullable Object key) {
201 return get(key) != null;
202 }
203
204 @Override
205 public boolean containsValue(@Nullable Object value) {
206 return values().contains(value);
207 }
208
209 private transient ImmutableSet<Entry<K, V>> cachedEntrySet = null;
210
211 public final ImmutableSet<Entry<K, V>> entrySet() {
212 if (cachedEntrySet != null) {
213 return cachedEntrySet;
214 }
215 return cachedEntrySet = createEntrySet();
216 }
217
218 abstract ImmutableSet<Entry<K, V>> createEntrySet();
219
220 private transient ImmutableSet<K> cachedKeySet = null;
221
222 public ImmutableSet<K> keySet() {
223 if (cachedKeySet != null) {
224 return cachedKeySet;
225 }
226 return cachedKeySet = createKeySet();
227 }
228
229 ImmutableSet<K> createKeySet() {
230 return new ImmutableMapKeySet<K, V>(this);
231 }
232
233 private transient ImmutableCollection<V> cachedValues = null;
234
235 public ImmutableCollection<V> values() {
236 if (cachedValues != null) {
237 return cachedValues;
238 }
239 return cachedValues = createValues();
240 }
241
242
243
244
245 private transient ImmutableSetMultimap<K, V> multimapView;
246
247 public ImmutableSetMultimap<K, V> asMultimap() {
248 ImmutableSetMultimap<K, V> result = multimapView;
249 return (result == null) ? (multimapView = createMultimapView()) : result;
250 }
251
252 private ImmutableSetMultimap<K, V> createMultimapView() {
253 ImmutableMap<K, ImmutableSet<V>> map = viewValuesAsImmutableSet();
254 return new ImmutableSetMultimap<K, V>(map, map.size(), null);
255 }
256
257 private ImmutableMap<K, ImmutableSet<V>> viewValuesAsImmutableSet() {
258 final Map<K, V> outer = this;
259 return new ImmutableMap<K, ImmutableSet<V>>() {
260 @Override
261 public int size() {
262 return outer.size();
263 }
264
265 @Override
266 public ImmutableSet<V> get(@Nullable Object key) {
267 V outerValue = outer.get(key);
268 return outerValue == null ? null : ImmutableSet.of(outerValue);
269 }
270
271 @Override
272 ImmutableSet<Entry<K, ImmutableSet<V>>> createEntrySet() {
273 return new ImmutableSet<Entry<K, ImmutableSet<V>>>() {
274 @Override
275 public UnmodifiableIterator<Entry<K, ImmutableSet<V>>> iterator() {
276 final Iterator<Entry<K,V>> outerEntryIterator = outer.entrySet().iterator();
277 return new UnmodifiableIterator<Entry<K, ImmutableSet<V>>>() {
278 @Override
279 public boolean hasNext() {
280 return outerEntryIterator.hasNext();
281 }
282
283 @Override
284 public Entry<K, ImmutableSet<V>> next() {
285 final Entry<K, V> outerEntry = outerEntryIterator.next();
286 return new AbstractMapEntry<K, ImmutableSet<V>>() {
287 @Override
288 public K getKey() {
289 return outerEntry.getKey();
290 }
291
292 @Override
293 public ImmutableSet<V> getValue() {
294 return ImmutableSet.of(outerEntry.getValue());
295 }
296 };
297 }
298 };
299 }
300
301 @Override
302 boolean isPartialView() {
303 return false;
304 }
305
306 @Override
307 public int size() {
308 return outer.size();
309 }
310 };
311 }
312
313 @Override
314 boolean isPartialView() {
315 return false;
316 }
317 };
318 }
319
320 ImmutableCollection<V> createValues() {
321 return new ImmutableMapValues<K, V>(this);
322 }
323
324 @Override public boolean equals(@Nullable Object object) {
325 return Maps.equalsImpl(this, object);
326 }
327
328 @Override public int hashCode() {
329
330
331 return entrySet().hashCode();
332 }
333
334 @Override public String toString() {
335 return Maps.toStringImpl(this);
336 }
337 }